package repostiory

import (
	"context"
	"gitee.com/chicken-c/go-learn/webook/internal/domain"
	"gitee.com/chicken-c/go-learn/webook/internal/repostiory/cache"
	"gitee.com/chicken-c/go-learn/webook/internal/repostiory/dao"
	"github.com/ecodeclub/ekit/slice"
)

type InterActiveRepository interface {
	BatchIncrReadCnt(ctx context.Context, bizs []string, bizIds []int64) error
	IncrReadCnt(ctx context.Context, biz string, bizId int64) error
	IncrLike(ctx context.Context, biz string, aId int64, uId int64) error
	DecrLike(ctx context.Context, biz string, aId int64, uId int64) error
	AddCollectionItem(ctx context.Context, biz string, id int64, cId int64, uId int64) error
	DeleteCollectionItem(ctx context.Context, biz string, id int64, cId int64, uId int64) error
	Get(ctx context.Context, biz string, id int64) (domain.InterActive, error)
	Liked(ctx context.Context, biz string, id int64, uId int64) (bool, error)
	Collectd(ctx context.Context, biz string, id int64, uId int64) (bool, error)
	GetByIds(ctx context.Context, biz string, ids []int64) ([]domain.InterActive, error)
}

type CachedInterActiveRepository struct {
	dao   dao.InterActiveDAO
	Cache cache.InterActiveCache
}

func (c *CachedInterActiveRepository) GetByIds(ctx context.Context, biz string, ids []int64) ([]domain.InterActive, error) {
	intrs, err := c.dao.GetByIds(ctx, biz, ids)
	if err != nil {
		return nil, err
	}

	return slice.Map(intrs, func(idx int, intr dao.InterActive) domain.InterActive {
		return domain.InterActive{
			BizId:      intr.BizId,
			ReadCnt:    intr.ReadCnt,
			LikeCnt:    intr.LikeCnt,
			CollectCnt: intr.CollectCnt,
		}
	}), nil
}

func (c *CachedInterActiveRepository) Liked(ctx context.Context, biz string, id int64, uId int64) (bool, error) {
	ul, err := c.dao.GetLikeInfo(ctx, biz, id, uId)
	if err != nil {
		return false, err
	}
	return ul.Status == 1, nil
}

func (c *CachedInterActiveRepository) Collectd(ctx context.Context, biz string, id int64, uId int64) (bool, error) {
	uc, err := c.dao.GetCollectInfo(ctx, biz, id, uId)
	if err != nil {
		return false, err
	}
	return uc.Status == 1, nil
}

func (c *CachedInterActiveRepository) Get(ctx context.Context, biz string, id int64) (domain.InterActive, error) {
	//先查缓存，在查db
	intr, err := c.Cache.Get(ctx, biz, id)
	if err == nil {
		return intr, nil
	}

	ie, err := c.dao.Get(ctx, biz, id)
	if err == nil {

		//回写到缓存
		err = c.Cache.Set(ctx, biz, id, domain.InterActive{
			ReadCnt:    ie.ReadCnt,
			LikeCnt:    ie.LikeCnt,
			CollectCnt: ie.CollectCnt,
		})
		if err != nil {
			//这个错误可以忽略
		}

		return domain.InterActive{
			ReadCnt:    ie.ReadCnt,
			LikeCnt:    ie.LikeCnt,
			CollectCnt: ie.CollectCnt,
		}, nil
	}

	return domain.InterActive{}, err
}

func NewCachedInterActiveRepository(dao dao.InterActiveDAO,
	cache cache.InterActiveCache) InterActiveRepository {
	return &CachedInterActiveRepository{
		dao:   dao,
		Cache: cache,
	}
}

func (c *CachedInterActiveRepository) AddCollectionItem(ctx context.Context, biz string, id int64, cId int64, uId int64) error {
	//先db,在cache
	err := c.dao.InsertCollectionItem(ctx, biz, id, uId)
	if err != nil {
		return err
	}

	return c.Cache.IncrCollectCntInPresent(ctx, biz, id)
}

func (c *CachedInterActiveRepository) DeleteCollectionItem(ctx context.Context, biz string, id int64, cId int64, uId int64) error {
	//TODO implement me
	panic("implement me")
}

func (c *CachedInterActiveRepository) IncrLike(ctx context.Context, biz string, aId int64, uId int64) error {
	err := c.dao.InsertLikeInfo(ctx, biz, aId, uId)
	if err != nil {
		return err
	}

	return c.Cache.IncrLikeCntInPresent(ctx, biz, aId)
}

func (c *CachedInterActiveRepository) DecrLike(ctx context.Context, biz string, aId int64, uId int64) error {
	err := c.dao.DeleteLikeInfo(ctx, biz, aId, uId)
	if err != nil {
		return err
	}

	return c.Cache.DecrLikeCntInPresent(ctx, biz, aId)
}

func (c *CachedInterActiveRepository) IncrReadCnt(ctx context.Context, biz string, bizId int64) error {
	//先更新db,在更新缓存
	err := c.dao.IncrReadCnt(ctx, biz, bizId)
	if err != nil {
		return err
	}

	return c.Cache.IncrReadCntInPresent(ctx, biz, bizId)
}

func (c *CachedInterActiveRepository) BatchIncrReadCnt(ctx context.Context, bizs []string, bizIds []int64) error {
	err := c.dao.BatchIncrReadCnt(ctx, bizs, bizIds)
	if err != nil {
		return err
	}

	go func() {
		//循环更新redis
		for i := 0; i < len(bizIds); i++ {
			er := c.Cache.IncrReadCntInPresent(ctx, bizs[i], bizIds[i])
			if er != nil {
				//记录日志
			}
		}
	}()

	return err
}
